qutebrowser ModeManager

In qutebrowser, there is a concept similar to Vim's Mode, with ModeManager responsible for mode management.

EventFilter.handle_event

Driven by keyboard input, when the EventFilter class receives a keyboard event, it will obtain the current modeman (ModeManager) for processing:

# EventFilter
def _handle_key_event(self, event: QKeyEvent) -> bool:
    active_window = objects.qapp.activeWindow()
    if active_window not in objreg.window_registry.values():
        return False
    try:
        man = modeman.instance('current')
        # handle key event by current ModeManger
        return man.handle_event(event)
    except objreg.RegistryUnavailableError:
        return False

ModeManager.handle_event

The handle_event method of ModeManager will use a table lookup method to find the corresponding handler and call it:

def handle_event(self, event: QEvent) -> bool:
    # Map
    handlers: Mapping[QEvent.Type, Callable[[QKeyEvent], bool]] = {
        QEvent.Type.KeyPress: self._handle_keypress,
        QEvent.Type.KeyRelease: self._handle_keyrelease,
        QEvent.Type.ShortcutOverride:
            functools.partial(self._handle_keypress, dry_run=True),
    }
    handler = handlers[event.type()]
    # call handler
    return handler(cast(QKeyEvent, event))

ModeManager listens for three types of events:

Handler Map

modeman.py 的 init 全局函数中,完成了向 ModeManager 中注册模式。具体代码如下:

def init(win_id: int, parent: QObject) -> 'ModeManager':
    """Initialize the mode manager and the keyparsers for the given win_id."""
    commandrunner = runners.CommandRunner(win_id)

    modeman = ModeManager(win_id, parent)
    objreg.register(
	    'mode-manager', 
		modeman, 
		scope='window', 
		window=win_id)

    hintmanager = hints.HintManager(win_id, parent=parent)
    objreg.register('hintmanager', hintmanager, scope='window',
                    window=win_id, command_only=True)
    modeman.hintmanager = hintmanager

    log_sensitive_keys = 'log-sensitive-keys' in objects.debug_flags

    keyparsers: ParserDictType = {
        usertypes.KeyMode.normal:
            modeparsers.NormalKeyParser(
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman),

        usertypes.KeyMode.hint:
            modeparsers.HintKeyParser(
                win_id=win_id,
                commandrunner=commandrunner,
                hintmanager=hintmanager,
                parent=modeman),

        usertypes.KeyMode.insert:
            modeparsers.CommandKeyParser(
                mode=usertypes.KeyMode.insert,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman,
                passthrough=True,
                do_log=log_sensitive_keys,
                supports_count=False),

        usertypes.KeyMode.passthrough:
            modeparsers.CommandKeyParser(
                mode=usertypes.KeyMode.passthrough,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman,
                passthrough=True,
                do_log=log_sensitive_keys,
                supports_count=False),

        usertypes.KeyMode.command:
            modeparsers.CommandKeyParser(
                mode=usertypes.KeyMode.command,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman,
                passthrough=True,
                do_log=log_sensitive_keys,
                supports_count=False),

        usertypes.KeyMode.prompt:
            modeparsers.CommandKeyParser(
                mode=usertypes.KeyMode.prompt,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman,
                passthrough=True,
                do_log=log_sensitive_keys,
                supports_count=False),

        usertypes.KeyMode.yesno:
            modeparsers.CommandKeyParser(
                mode=usertypes.KeyMode.yesno,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman,
                supports_count=False),

        usertypes.KeyMode.caret:
            modeparsers.CommandKeyParser(
                mode=usertypes.KeyMode.caret,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman,
                passthrough=True),

        usertypes.KeyMode.set_mark:
            modeparsers.RegisterKeyParser(
                mode=usertypes.KeyMode.set_mark,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman),

        usertypes.KeyMode.jump_mark:
            modeparsers.RegisterKeyParser(
                mode=usertypes.KeyMode.jump_mark,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman),

        usertypes.KeyMode.record_macro:
            modeparsers.RegisterKeyParser(
                mode=usertypes.KeyMode.record_macro,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman),

        usertypes.KeyMode.run_macro:
            modeparsers.RegisterKeyParser(
                mode=usertypes.KeyMode.run_macro,
                win_id=win_id,
                commandrunner=commandrunner,
                parent=modeman),
    }

    for mode, parser in keyparsers.items():
        modeman.register(mode, parser)

    return modeman

本文作者:Maeiee

本文链接:qutebrowser ModeManager

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!